This chapter shows you the steps to follow to create a distributed version of the classic Hello World program using Java Remote Method Invocation (RMI).
The distributed Hello World example uses an applet to make a remote method call to the server from which it was downloaded to retrieve the message "Hello World!". When the applet runs, the message is displayed on the client.
examples.hello
and the root directory is $HOME/java/mysrc/examples/hello
.For example, to create the directory for your source files on Solaris, execute this command:
mkdir $HOME/java/mysrc/examples/hello
java.rmi.Remote
.
java.rmi.RemoteException
in its throws clause, in addition to any application-specific exceptions.
sayHello
, which returns a string to the caller:package examples.hello; public interface Hello extends java.rmi.Remote { String sayHello() throws java.rmi.RemoteException; }
HelloImpl.java
file, which contains the code for the Hello World server. The code is followed by an explanation of each of the preceding six steps.package examples.hello; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class HelloImpl extends UnicastRemoteObject implements Hello { private String name; public HelloImpl(String s) throws RemoteException { super(); name = s; } public String sayHello() throws RemoteException { return "Hello World!"; }
public static void main(String args[]) { // Create and install a security manager System.setSecurityManager(new RMISecurityManager()); try { HelloImpl obj = new HelloImpl("HelloServer"); Naming.rebind("//myhost/HelloServer", obj); System.out.println("HelloServer bound in registry"); } catch (Exception e) { System.out.println("HelloImpl err: " + e.getMessage()); e.printStackTrace(); } } }
HelloImpl
. An implementation class specifies the remote interface(s) it is implementing. It can also optionally indicate the remote server that it is extending, in this example java.rmi.server.UnicastRemoteObject
. Here is the HelloImpl
class declaration:public class HelloImpl implements Hello extends java.rmi.server.UnicastRemoteObject
UnicastRemoteObject
indicates that the HelloImpl
class is used to create a single (non-replicated) remote object that uses RMI's default sockets-based transport for communication. If you choose to extend a remote object from a non-remote class, you need to explicitly export the remote object by calling the method UnicastRemoteObject.exportObject
.
Here is the constructor for the HelloImpl
class, which initializes the private string variable name
with the name of the remote object:
private String name; public HelloImpl(String s) throws java.rmi.RemoteException { super(); name = s; }
super
method call invokes the no-arg constructor of java.rmi.server.UnicastRemoteObject
, which "exports" the remote object by listening for incoming calls to the remote object on an anonymous port.
java.rmi.RemoteException
, because RMI's attempt to export a remote object during construction may fail if communication resources are not available.
super
no-arg constructor occurs by default if omitted, it is included in this example to make clear the fact that Java constructs the superclass before the class.
For example, here is the implementation for the sayHello
method, which returns the string Hello World!
to the caller.
public String sayHello() throws RemoteException { return "Hello World!"; }
java.io.Serializable
. Most of the core Java classes in java.lang
and java.util
implement the Serializable
interface.main
method of the service first needs to create and install a security manager, either the RMISecurityManager
or one that you have defined yourself. For example:System.setSecurityManager(new RMISecurityManager());
main
method of the service needs to create one or more instances of the remote object which provides the service. For example:HelloImpl obj = new HelloImpl("HelloServer");
For bootstrapping, the RMI system also provides a URL-based registry that allows you to bind a URL of the form //host/objectname
to the remote object, where objectname
is a simple string name. Once a remote object is registered on the server, callers can look up the object by name, obtain a remote object reference, and then remotely invoke methods on the object.
For example, the following code binds the URL of the remote object named HelloServer
to a reference for the remote object:
Naming.rebind("//myhost/HelloServer", obj);
obj
argument. Remote implementation objects like instances of HelloImpl
never leave the VM where they are created, so when a client performs a lookup in a server's remote object registry, a reference to the stub is returned.
sayHello
method in order to get the string "Hello World!", which is displayed when the applet runs. Here is the code for the applet:package examples.hello; import java.awt.*; import java.rmi.*; public class HelloApplet extends java.applet.Applet { String message = ""; public void init() { try { Hello obj = (Hello)Naming.lookup("//" + getCodeBase().getHost() + "/HelloServer"); message = obj.sayHello(); } catch (Exception e) { System.out.println("HelloApplet exception: " + e.getMessage()); e.printStackTrace(); } } public void paint(Graphics g) { g.drawString(message, 25, 50); } }
getCodeBase
method in conjunction with the getHost
method.
sayHello
method of the HelloServer remote object and stores the return value from the call (the string "Hello World!") in a variable named message
.
paint
method to draw the applet on the display, causing the string "Hello World!" to be displayed.
AppletSecurityManager
will throw an exception since the applet cannot access the local system, but is instead limited to communicating only with applet host.<HTML> <title>Hello World</title> <center> <h1>Hello World</h1> </center> The message from the HelloServer is: <p> <applet codebase="../.." code="examples.hello.HelloApplet" width=500 height=120> </applet> </HTML>
codebase
attribute indicates the URL, as shown here:
code
attribute specifies the fully package qualified name of the applet, in this example examples.hello.HelloApplet
:
$HOME/java/mysrc/hello
directory has four files:Hello.java
, which contains the source code for the Hello remote interface.
HelloImpl.java
, which is the source code for the HelloImpl remote object implementation, the server for the Hello World applet.
HelloApplet.java
, which is the source code for the applet.
index.html
, which is the web page that references the Hello World applet.
.java
source files to create .class
files. You then run the rmic
compiler to create stubs and skeletons. A stub is a client-side proxy for a remote object which forwards RMI calls to the server-side skeleton, which in turn forwards the call to the actual remote object implementation.
When you use the javac
and rmic
compilers, you must specify where the resulting class files should reside. For applets, all files should be in the applet's codebase directory. In this chapter, this is $HOME/public_html/codebase
.
Some Web servers allow accessing a user's public_html diretory via an HTTP URL constructed as "http://host/~username/". If your Web server does not support this convention, you may use a file URL of the form "file://home/username/public_html".
$HOME/public_html/codebase
and the development directory $HOME/java/mysrc/examples/hello
are each visible via the local CLASSPATH
on the development machine.
To compile the Java source files, run the javac
command as follows:
javac -d $HOME/public_html/codebase Hello.java HelloImpl.java HelloApplet.java
examples/hello
(if it does not already exist) in the directory $HOME/public_html/codebase
. The command then writes to that directory the files Hello.class
, HelloImpl.class
, and HelloApplet.class
. These are the remote interface, the server, and the applet respectively.rmic
compiler on the names of compiled class files that contain remote object implementations. rmic
takes one or more class names as input and produces as output class files of the form myImpl
_Skel.class
and myImpl
_Stub.class
.
For example, to create the stub and skeleton for the HelloImpl remote object implementation, run rmic
like this:
rmic -d $HOME/public_html/codebase examples.hello.HelloImpl
-d
option indicates the root directory in which to place the compiled stub and skeleton files. So the preceding command creates the following files in the directory $HOME/public_html/codebase/examples/hello
:
Note that the generated stub implements exactly the same set of remote interfaces as the remote object itself. This means that a client can use the Java language's built-in operators for casting and type checking. It also means that Java remote objects support true object-oriented polymorphism.index.html
file must be moved from the development directory to the codebase
directory. For example:mv $HOME/java/mysrc/examples/hello/index.html $HOME/public_html/codebase/examples/hello
HOME/public_html/codebase
directory is available via the server's local CLASSPATH
when you run the HelloImpl server.
To start the registry on the server, execute the rmiregistry
command. This command produces no output and is typically run in the background. For example, on Windows 95 or Windows NT:
start rmiregistry
javaw
if start is not available)rmiregistry &
start rmiregistry 2001
java.rmi.Naming
class when making calls to the registry. For example, if the registry is running on port 2001 in the Hello World example, here is the call required to bind the URL of the HelloServer to the remote object reference:Naming.rebind("//myhost:2001/HelloServer", obj);
<PARAM name="url" value="//myhost:2001/HelloServer">
java.rmi.server.codebase
property must be specified, so that references to the remote objects created by the server can include the URL from which the stub class can be dynamically downloaded to the client.The following command shows how to start the HelloImpl server, specifying this property:
java -Djava.rmi.server.codebase=http://myhost/~myusrname/codebase/ examples.hello.HelloImpl &
/
in the codebase
URL must be specified.A stub class is dynamically loaded into a client's virtual machine only when the class is not already available locally.
Once the registry and server are running, the applet can be run. An applet is run by loading its web page into a browser or appletviewer, as shown here:
appletviewer http://myhost/~myusrname/codebase/examples/hello/index.html &